/*************************************************************************
 *                                                                       *
 * This file is part of the DogosFrame distribution.  For full copyright *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 *                                                                       *
 *************************************************************************/

#ifndef DOGOS_include_COMMON_math_VectorValue_h
#define DOGOS_include_COMMON_math_VectorValue_h

//COMMON headers
#include "COMMON/math/TypeVector.h"

namespace DOGOS
{

/**
 * This class defines a vector in 3 dimensional Real or Complex
 * space.  The typedef RealVectorValue always defines a real-valued vector,
 * and NumberVectorValue defines a real or complex-valued vector depending
 * on how the library was configured.
 *
 * \author Benjamin S. Kirk
 * \date 2003
 */
template <typename T>
class VectorValue : public TypeVector<T>
{
public:

    /**
     * Empty constructor.
     * Gives the vector 0 in \p 3 dimensional T space.
     */
    VectorValue ();

    /**
     * Constructor-from-T.  By default sets higher dimensional
     * entries to 0.
     */
    VectorValue (const T x,
                 const T y=0,
                 const T z=0);

    /**
     * Constructor-from-scalars.  By default sets higher dimensional
     * entries to 0.
     */
    template <typename Scalar1, typename Scalar2, typename Scalar3>
    VectorValue (typename
                 boostcopy::enable_if_c<ScalarTraits<Scalar1>::value,
                 const Scalar1>::type x,
                 typename
                 boostcopy::enable_if_c<ScalarTraits<Scalar2>::value,
                 const Scalar2>::type y = 0,
                 typename
                 boostcopy::enable_if_c<ScalarTraits<Scalar3>::value,
                 const Scalar3>::type z = 0);


    /**
     * Constructor-from-scalar.  Sets higher dimensional entries to 0.
     * Necessary because for some reason the constructor-from-scalars
     * alone is insufficient to let the compiler figure out
     * VectorValue<Complex> v = 0;
     */
    template <typename Scalar>
    VectorValue (const Scalar x,
                 typename
                 boostcopy::enable_if_c<ScalarTraits<Scalar>::value,
                 const Scalar>::type * sfinae = DOGOS_NULL_PTR);


    /**
     * Copy-constructor.
     */
    template <typename T2>
    VectorValue (const VectorValue<T2> & p);

    /**
     * Copy-constructor.
     */
    template <typename T2>
    VectorValue (const TypeVector<T2> & p);

#ifdef LIBMESH_USE_COMPLEX_NUMBERS
    /**
     * Constructor that takes two \p TypeVector<Real>
     * representing the real and imaginary part as
     * arguments.
     */
    VectorValue (const TypeVector<Real> & p_re,
                 const TypeVector<Real> & p_im);
#endif

    /**
     * Assignment-from-scalar operator.  Used only to zero out vectors.
     */
    template <typename Scalar>
    typename boostcopy::enable_if_c<
    ScalarTraits<Scalar>::value,
                 VectorValue &>::type
                 operator = (const Scalar & p)
    { TBOX_ASSERT_EQ (p, Scalar(0)); this->zero(); return *this; }
};



/**
 * Useful typedefs to allow transparent switching
 * between Real and Complex data types.
 */
typedef VectorValue<double> RealVectorValue;
typedef RealVectorValue     RealGradient;



//------------------------------------------------------
// Inline functions

template <typename T>
inline
VectorValue<T>::VectorValue () :
    TypeVector<T> ()
{
}


template <typename T>
inline
VectorValue<T>::VectorValue (const T x,
                             const T y,
                             const T z) :
    TypeVector<T> (x,y,z)
{
}



template <typename T>
template <typename Scalar1, typename Scalar2, typename Scalar3>
inline
VectorValue<T>::VectorValue (typename
                             boostcopy::enable_if_c<ScalarTraits<Scalar1>::value,
                             const Scalar1>::type x,
                             typename
                             boostcopy::enable_if_c<ScalarTraits<Scalar2>::value,
                             const Scalar2>::type y,
                             typename
                             boostcopy::enable_if_c<ScalarTraits<Scalar3>::value,
                             const Scalar3>::type z) :
    TypeVector<T> (x,y,z)
{
}


template <typename T>
template <typename Scalar>
inline
VectorValue<T>::VectorValue (const Scalar x,
                             typename
                             boostcopy::enable_if_c<ScalarTraits<Scalar>::value,
                             const Scalar>::type * /*sfinae*/) :
    TypeVector<T> (x)
{
}

template <typename T>
template <typename T2>
inline
VectorValue<T>::VectorValue (const VectorValue<T2> & p) :
    TypeVector<T> (p)
{
}



template <typename T>
template <typename T2>
inline
VectorValue<T>::VectorValue (const TypeVector<T2> & p) :
    TypeVector<T> (p)
{
}

#ifdef LIBMESH_USE_COMPLEX_NUMBERS
template <typename T>
inline
VectorValue<T>::VectorValue (const TypeVector<Real> & p_re,
                             const TypeVector<Real> & p_im) :
    TypeVector<T> (Complex (p_re(0), p_im(0)),
                   Complex (p_re(1), p_im(1)),
                   Complex (p_re(2), p_im(2)))
{}
#endif


} // namespace DOGOS

#include "COMMON/math/VectorValue.inl"

#endif
